﻿using System;
using System.Diagnostics.Contracts;
using System.Threading;

namespace DaveSexton.Labs
{
	internal abstract class InputAcquirer : IDisposable
	{
		#region Public Properties
		public bool HasValue
		{
			get
			{
				Contract.Ensures(Contract.Result<bool>() == hasValue);

				return hasValue;
			}
		}
		#endregion

		#region Private / Protected
		private readonly ManualResetEvent acquiredSignal = new ManualResetEvent(false);
		private bool hasValue;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="InputAcquirer" /> class for derived classes.
		/// </summary>
		protected InputAcquirer()
		{
			Contract.Ensures(!HasValue);
		}
		#endregion

		#region Methods
		[ContractInvariantMethod]
		[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
		private void ObjectInvariant()
		{
			Contract.Invariant(acquiredSignal != null);
		}

		public void Acquire()
		{
			Contract.Ensures(HasValue);

			acquiredSignal.WaitOne();

			Contract.Assume(HasValue);
		}

		public void Dispose()
		{
			acquiredSignal.Dispose();
		}

		protected void SetHasValue()
		{
			Contract.Requires(!HasValue);
			Contract.Ensures(HasValue);

			hasValue = true;

			acquiredSignal.Set();
		}
		#endregion
	}
}